/*******************************************************************************
  * 文件：UartComm_Message.c
  * 作者：zyz
  * 版本：v1.0.0
  * 日期：2017-08-03
  * 说明：消息
*******************************************************************************/

/* 头文件 *********************************************************************/
#include "UartComm_Message.h"
#include "UartComm_Driver.h"
#include "UartComm.h"
#include "main.h"
#include "JumpFunction.h"

/* 宏定义 *********************************************************************/
/* 类型定义 *******************************************************************/
/* 变量定义 *******************************************************************/
/* 函数声明 *******************************************************************/
/* 函数定义 *******************************************************************/
/*******************************************************************************
  * 函数名: UartComm_InitMessage
  * 功  能：初始化消息
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void UartComm_InitMessage(void)
{
    // 初始化DBA
    UartComm_InitDba();
}

/*******************************************************************************
  * 函数名：UartComm_SendBroadcastProtocolInfoMsg
  * 功  能：发送广播协议信息消息
  * 参  数：无
  * 返回值：无
  * 说  明：发送 命令0x00
*******************************************************************************/
void UartComm_SendBroadcastProtocolInfoMsg(void)
{
    U8 *pu8Data;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(0,
        u8UARTCOMM_BROADCAST_ADDR, u8UARTCOMM_CMD_BCST_PROT_INFO);

    // 协议信息
    *pu8Data++ = u8PROT_MAJOR_VERSION;     // 协议主版本
    *pu8Data++ = u8PROT_MINOR_VERSION;     // 协议次版本
    *pu8Data++ = u8DATA_MAJOR_VERSION;     // 数据主版本
    *pu8Data++ = u8DATA_MINOR_VERSION;     // 数据次版本

    // 发送数据包
    UartComm_SendPacket(ePORT_SUM, pu8Data);
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqInquireSwVerMsg
  * 功  能：接收请求查询软件版本消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0x01
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqInquireSwVerMsg)
{
    U8* pu8Data;
    LittleEndianU16_tu uYear;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_INQUIRE_SW_VER);
    // 版本
    *pu8Data++ = u8SW_MAJOR_VERSION;             // 主版本
    *pu8Data++ = u8SW_MINOR_VERSION;             // 次版本
    *pu8Data++ = u8SW_REVISION_VERSION;          // 修订版本
    uYear.u16Word = u16SW_EXTENDED_VERSION_YEAR;
    *pu8Data++ = uYear.sByte.u8Msb;              // 延伸版本，年MSB
    *pu8Data++ = uYear.sByte.u8Lsb;              // 延伸版本，年LSB
    *pu8Data++ = u8SW_EXTENDED_VERSION_MONTH;    // 延伸版本，月
    *pu8Data++ = u8SW_EXTENDED_VERSION_DAY;      // 延伸版本，日
    // 发送响应读数据包
    UartComm_SendPacket(ePort, pu8Data);
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqInquireSwIdMsg
  * 功  能：接收请求查询软件标识符消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0x03
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqInquireSwIdMsg)
{
    U8* pu8Data;
    U8 u8Len;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_INQUIRE_SW_ID);
    // 软件标识符
    u8Len = (U8)strlen(strSW_ID);
    memcpy(pu8Data, strSW_ID, u8Len);
    pu8Data += u8Len;
    // 发送响应读数据包
    UartComm_SendPacket(ePort, pu8Data);
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqHeartbeatMsg
  * 功  能：接收请求心跳消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0x11
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqHeartbeatMsg)
{
    U8 *pu8Data;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_HEARTBEAT);
    // 发送响应读数据包
    UartComm_SendPacket(ePort, pu8Data);

    // 清除通信故障
    UartComm_ClearCommError();
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqReadDbaMsg
  * 功  能：接收请求读DBA消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xD1
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqReadDbaMsg)
{
    U8 u8Index;
    U8 *pu8Data;
    U8 *pu8ReqDataEnd;
    U8 *pu8ResDataEnd;
    U8 u8ReqDataBlockNum;
    UartCommDataBlock_ts *psReqDataBlock;
    UartCommDataBlock_ts *psResDataBlock;
    UartCommDbaMsgData_ts *psResDbaMsgData;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_READ_DBA);

    // 计算请求数据末端位置
    // 及响应数据最远位置
    pu8ReqDataEnd = (U8*)((U8*)&(psPacket->uData) + psPacket->u8DataLen);
    pu8ResDataEnd = (U8*)(pu8Data + u8UARTCOMM_MAX_DATA_LEN);

    // 获取请求数据块及个数
    u8ReqDataBlockNum = psPacket->uData.sDbaMsgData.u8DataBlockNum;
    psReqDataBlock = (UartCommDataBlock_ts*)psPacket->uData.sDbaMsgData.au8Data;
    // 初始化响应数据块参数
    psResDbaMsgData = (UartCommDbaMsgData_ts*)pu8Data;
    psResDbaMsgData->u8DataBlockNum = 0;
    psResDataBlock = (UartCommDataBlock_ts*)psResDbaMsgData->au8Data;

    // 遍历数据块
    for(u8Index = 0;
        (u8Index < u8ReqDataBlockNum) &&
        (pu8ReqDataEnd >= (psReqDataBlock->au8Data)) &&
        (pu8ResDataEnd >= (psResDataBlock->au8Data + psReqDataBlock->u8DataLen));
        u8Index++)
    {
        LittleEndianU16_tu uAddr;

        // 地址转换
        uAddr.sByte.u8Msb = psReqDataBlock->u8DataAddrMsb;
        uAddr.sByte.u8Lsb = psReqDataBlock->u8DataAddrLsb;

        // 设置响应数据块地址
        psResDataBlock->u8DataAddrMsb = psReqDataBlock->u8DataAddrMsb;
        psResDataBlock->u8DataAddrLsb = psReqDataBlock->u8DataAddrLsb;

        // 读设备状态数据块
        psResDataBlock->u8DataLen = UartComm_ReadWriteDeviceStateDataBlock(
            eDATA_READ,
            uAddr.u16Word, psReqDataBlock->u8DataLen, psResDataBlock->au8Data);

        // 获取下一个请求数据块
        psReqDataBlock = (UartCommDataBlock_ts*)(psReqDataBlock->au8Data);
        // 更新响应数据块个数及下一个响应数据块
        if(psResDataBlock->u8DataLen != 0)
        {
            psResDbaMsgData->u8DataBlockNum++;
            psResDataBlock = (UartCommDataBlock_ts*)(psResDataBlock->au8Data +
                                                     psResDataBlock->u8DataLen);
        }
    }

    // 更新发送数据位置
    // 发送响应读数据包
    pu8Data = (U8*)psResDataBlock;
    UartComm_SendPacket(ePort, pu8Data);
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqWriteDbaMsg
  * 功  能：接收请求写DBA消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xD3
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqWriteDbaMsg)
{
    U8 u8Index;
    U8 *pu8Data;
    U8 *pu8ReqDataEnd;
    U8 *pu8ResDataEnd;
    U8 u8ReqDataBlockNum;
    UartCommDataBlock_ts *psReqDataBlock;
    UartCommDataBlock_ts *psResDataBlock;
    UartCommDbaMsgData_ts *psResDbaMsgData;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_WRITE_DBA);

    // 计算请求数据末端位置
    // 及响应数据最远位置
    pu8ReqDataEnd = (U8*)((U8*)&(psPacket->uData) + psPacket->u8DataLen);
    pu8ResDataEnd = (U8*)(pu8Data + u8UARTCOMM_MAX_DATA_LEN);

    // 获取请求数据块及个数
    u8ReqDataBlockNum = psPacket->uData.sDbaMsgData.u8DataBlockNum;
    psReqDataBlock = (UartCommDataBlock_ts*)psPacket->uData.sDbaMsgData.au8Data;
    // 初始化响应数据块参数
    psResDbaMsgData = (UartCommDbaMsgData_ts*)pu8Data;
    psResDbaMsgData->u8DataBlockNum = 0;
    psResDataBlock = (UartCommDataBlock_ts*)psResDbaMsgData->au8Data;

    // 遍历数据块
    for(u8Index = 0;
        (u8Index < u8ReqDataBlockNum) &&
        (pu8ReqDataEnd >= (psReqDataBlock->au8Data + psReqDataBlock->u8DataLen)) &&
        (pu8ResDataEnd >= (psResDataBlock->au8Data));
        u8Index++)
    {
        LittleEndianU16_tu uAddr;

        // 地址转换
        uAddr.sByte.u8Msb = psReqDataBlock->u8DataAddrMsb;
        uAddr.sByte.u8Lsb = psReqDataBlock->u8DataAddrLsb;

        // 设置响应数据块地址
        psResDataBlock->u8DataAddrMsb = psReqDataBlock->u8DataAddrMsb;
        psResDataBlock->u8DataAddrLsb = psReqDataBlock->u8DataAddrLsb;

        // 写设备控制数据块
        psResDataBlock->u8DataLen = UartComm_ReadWriteDeviceControlDataBlock(
            eDATA_WRITE,
            uAddr.u16Word, psReqDataBlock->u8DataLen, psReqDataBlock->au8Data);

        // 获取下一个请求数据块
        psReqDataBlock = (UartCommDataBlock_ts*)(psReqDataBlock->au8Data +
                                                 psReqDataBlock->u8DataLen);
        // 更新响应数据块个数及下一个响应数据块
        if(psResDataBlock->u8DataLen != 0)
        {
            psResDbaMsgData->u8DataBlockNum++;
            psResDataBlock = (UartCommDataBlock_ts*)(psResDataBlock->au8Data);
        }
    }

    // 更新发送数据位置
    // 发送响应写数据包
    pu8Data = (U8*)psResDataBlock;
    UartComm_SendPacket(ePort, pu8Data);

    // 处理负载控制
    if(ePort == ePORT_DISPLAY_BOARD)
    {
        UartComm_HandleLoadControl();
    }
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqBitsWriteDbaMsg
  * 功  能：接收请求位写入DBA消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xD7
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqBitsWriteDbaMsg)
{
    U8 u8Index;
    U8 *pu8Data;
    U8 *pu8ReqDataEnd;
    U8 *pu8ResDataEnd;
    U8 u8ReqDataBlockNum;
    UartCommDataBlock_ts *psReqDataBlock;
    UartCommDataBlock_ts *psResDataBlock;
    UartCommDbaMsgData_ts *psResDbaMsgData;

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_BITS_WRITE_DBA);

    // 计算请求数据末端位置
    // 及响应数据最远位置
    pu8ReqDataEnd = (U8*)((U8*)&(psPacket->uData) + psPacket->u8DataLen);
    pu8ResDataEnd = (U8*)(pu8Data + u8UARTCOMM_MAX_DATA_LEN);

    // 获取请求数据块及个数
    u8ReqDataBlockNum = psPacket->uData.sDbaMsgData.u8DataBlockNum;
    psReqDataBlock = (UartCommDataBlock_ts*)psPacket->uData.sDbaMsgData.au8Data;
    // 初始化响应数据块参数
    psResDbaMsgData = (UartCommDbaMsgData_ts*)pu8Data;
    psResDbaMsgData->u8DataBlockNum = 0;
    psResDataBlock = (UartCommDataBlock_ts*)psResDbaMsgData->au8Data;

    // 遍历数据块
    for(u8Index = 0;
        (u8Index < u8ReqDataBlockNum) &&
        (pu8ReqDataEnd >= (psReqDataBlock->au8Data + (psReqDataBlock->u8DataLen)*2)) &&
        (pu8ResDataEnd >= (psResDataBlock->au8Data));
        u8Index++)
    {
        LittleEndianU16_tu uAddr;

        // 地址转换
        uAddr.sByte.u8Msb = psReqDataBlock->u8DataAddrMsb;
        uAddr.sByte.u8Lsb = psReqDataBlock->u8DataAddrLsb;

        // 设置响应数据块地址
        psResDataBlock->u8DataAddrMsb = psReqDataBlock->u8DataAddrMsb;
        psResDataBlock->u8DataAddrLsb = psReqDataBlock->u8DataAddrLsb;

        // 写设备控制数据块
        psResDataBlock->u8DataLen = UartComm_ReadWriteDeviceControlDataBlock(
            eDATA_BITS_WRITE,
            uAddr.u16Word, psReqDataBlock->u8DataLen, psReqDataBlock->au8Data);

        // 获取下一个请求数据块
        psReqDataBlock = (UartCommDataBlock_ts*)(psReqDataBlock->au8Data +
                                                 (psReqDataBlock->u8DataLen)*2);
        // 更新响应数据块个数及下一个响应数据块
        if(psResDataBlock->u8DataLen != 0)
        {
            psResDbaMsgData->u8DataBlockNum++;
            psResDataBlock = (UartCommDataBlock_ts*)(psResDataBlock->au8Data);
        }
    }

    // 更新发送数据位置
    // 发送响应写数据包
    pu8Data = (U8*)psResDataBlock;
    UartComm_SendPacket(ePort, pu8Data);

    // 处理负载控制
    if(ePort == ePORT_DISPLAY_BOARD)
    {
        UartComm_HandleLoadControl();
    }
}

/*******************************************************************************
  * 函数名：UartComm_RecvReqSubscribeDbaMsg
  * 功  能：接收请求订阅DBA消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xD5
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvReqSubscribeDbaMsg)
{
    U8 u8Index;
    U8 *pu8Data;
    Bool bResult;
    U8 *pu8ReqDataEnd;
    U8 *pu8ResDataEnd;
    U8 u8SubscribeTime;
    U8 u8ReqDataBlockNum;
    UartCommDbaMsgData_ts *psResDbaMsgData;
    UartCommDataBlock_ts *psReqDataBlock;
    UartCommDataBlock_ts *psResDataBlock;

    // 停止发布DBA数据
    UartComm_PublishDbaData(ePort, FALSE);

    // 获取请求参数
    u8SubscribeTime = psPacket->uData.sComMsgData.au8Data[0];
    u8ReqDataBlockNum = psPacket->uData.sComMsgData.au8Data[1];
    psReqDataBlock = (UartCommDataBlock_ts*)&(psPacket->uData.sComMsgData.au8Data[2]);

    // 构建发送数据包
    pu8Data = UartComm_SetupSendPacket(psPacket->u8SeqNum,
        psPacket->u8SrcAddr, u8UARTCOMM_CMD_RES_SUBSCRIBE_DBA);

    // 计算请求数据末端位置
    // 及响应数据最远位置
    pu8ReqDataEnd = (U8*)((U8*)&(psPacket->uData) + psPacket->u8DataLen);
    pu8ResDataEnd = (U8*)(pu8Data + u8UARTCOMM_MAX_DATA_LEN);

    // 设置订阅时间
    *pu8Data++ = u8SubscribeTime;

    // 初始化响应参数
    psResDbaMsgData = (UartCommDbaMsgData_ts*)pu8Data;
    psResDbaMsgData->u8DataBlockNum = 0;
    psResDataBlock = (UartCommDataBlock_ts*)(psResDbaMsgData->au8Data);

    // 遍历数据块
    for(u8Index = 0;
        (u8Index < u8ReqDataBlockNum) &&
        (pu8ReqDataEnd >= (psReqDataBlock->au8Data)) &&
        (pu8ResDataEnd >= (psResDataBlock->au8Data));
        u8Index++)
    {
        LittleEndianU16_tu uAddr;

        // 地址转换
        uAddr.sByte.u8Msb = psReqDataBlock->u8DataAddrMsb;
        uAddr.sByte.u8Lsb = psReqDataBlock->u8DataAddrLsb;

        // 设置响应数据块地址
        psResDataBlock->u8DataAddrMsb = psReqDataBlock->u8DataAddrMsb;
        psResDataBlock->u8DataAddrLsb = psReqDataBlock->u8DataAddrLsb;

        // 读设备状态数据块
        psResDataBlock->u8DataLen = UartComm_ReadWriteDeviceStateDataBlock(
            eDATA_READ,
            uAddr.u16Word, psReqDataBlock->u8DataLen, psResDataBlock->au8Data);

        // 获取下一个请求数据块
        psReqDataBlock = (UartCommDataBlock_ts*)(psReqDataBlock->au8Data);
        // 更新响应数据块个数及下一个响应数据块
        if(psResDataBlock->u8DataLen != 0)
        {
            psResDbaMsgData->u8DataBlockNum++;
            psResDataBlock = (UartCommDataBlock_ts*)(psResDataBlock->au8Data);
        }
    }

    // 更新发送数据位置
    // 发送响应订阅数据包
    pu8Data = (U8*)psResDataBlock;
    UartComm_SendPacket(ePort, pu8Data);

    // 设置订阅DBA参数
    bResult = UartComm_SetSubscribeDbaParm(
        ePort, psPacket->u8SrcAddr, u8SubscribeTime,
        psResDbaMsgData->u8DataBlockNum, psResDbaMsgData->au8Data);

    // 设置成功，发布DBA数据
    if(bResult)
    {
        UartComm_PublishDbaData(ePort, TRUE);
    }
}

/*******************************************************************************
  * 函数名：UartComm_RecvNotifyDbaMsg
  * 功  能：接收通知DBA消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xDE
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvNotifyDbaMsg)
{
    U8 u8Index;
    U8 *pu8DataEnd;
    U8 u8DataBlockNum;
    UartCommDataBlock_ts *psDataBlock;

    // 计算数据末端位置
    pu8DataEnd = (U8*)((U8*)&(psPacket->uData) + psPacket->u8DataLen);

    // 获取数据块及个数
    u8DataBlockNum = psPacket->uData.sDbaMsgData.u8DataBlockNum;
    psDataBlock = (UartCommDataBlock_ts*)psPacket->uData.sDbaMsgData.au8Data;

    // 遍历数据块
    for(u8Index = 0;
        (u8Index < u8DataBlockNum) &&
        (pu8DataEnd >= (psDataBlock->au8Data + psDataBlock->u8DataLen));
        u8Index++)
    {
        LittleEndianU16_tu uAddr;

        // 地址转换
        uAddr.sByte.u8Msb = psDataBlock->u8DataAddrMsb;
        uAddr.sByte.u8Lsb = psDataBlock->u8DataAddrLsb;

        // 写设备控制数据块
        UartComm_ReadWriteDeviceControlDataBlock(
            eDATA_WRITE,
            uAddr.u16Word, psDataBlock->u8DataLen, psDataBlock->au8Data);

        // 获取下一个数据块
        psDataBlock = (UartCommDataBlock_ts*)(psDataBlock->au8Data +
                                              psDataBlock->u8DataLen);
    }

    // 处理负载控制
    if(ePort == ePORT_DISPLAY_BOARD)
    {
        UartComm_HandleLoadControl();
    }
}

/*******************************************************************************
  * 函数名：UartComm_RecvOtaReqNotifyUpgradeMsg
  * 功  能：接收OTA请求通知升级消息
  * 参  数：ePort    - 端口
  *         psPacket - 接收数据包指针
  * 返回值：无
  * 说  明：接收 命令0xA1
*******************************************************************************/
UARTCOMM_MSG_HANDLER(UartComm_RecvOtaReqNotifyUpgradeMsg)
{
    // 跳转到bootloader处理
    JumpToBootloader();
}

/***************************** 文件结束 ***************************************/
